﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

using Utils;

namespace MicroApi.Core.Filters
{
    public class ActionResultFilter : IActionFilter
    {
        #region 私有

        private readonly static Dictionary<string, string> tranle = new Dictionary<string, string>() {
            { "Could not convert ", "参数类型无效：{0}" },
            { "Error converting value","类型转换失败:{0}"}
        };
        private string GetLast(string key)
        {
            return key.Split('.').LastOrDefault();
        }

        private bool TryGetMessage(ModelError modelError, string key, out string message)
        {
            message = null;
            if (modelError == null) return false;
            message = modelError.ErrorMessage;
            if (modelError.Exception != null)
            {
                var e = modelError.Exception.InnerException ?? modelError.Exception;
                message = e.Message;
            }
            if (!string.IsNullOrEmpty(message))
            {
                foreach (var item in tranle)
                {
                    if (message.StartsWith(item.Key))
                    {
                        message = string.Format(item.Value, key);
                        break;
                    }
                }
                return true;
            }
            message = null;
            return false;
        }


        private void ReOnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext.HttpContext.Response.HasStarted)
            {
                return;
            }
            if (actionExecutedContext.Result is EmptyResult)
            {
                actionExecutedContext.Result = new ObjectResult(Result.Ok());
            }
            else if (actionExecutedContext.Result is ObjectResult objectResult)
            {
                if (objectResult.Value is Result)
                {
                    return;
                }
                else
                {
                    actionExecutedContext.Result = new ObjectResult(Result.Ok(objectResult.Value));
                }
            }
        }

        #endregion

        public void OnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext.Exception == null)
            {
                ReOnActionExecuted(actionExecutedContext);
            }
        }

        public void OnActionExecuting(ActionExecutingContext actionContext)
        { 
            if (DateTimeOffset.TryParse(actionContext.HttpContext.Request.Headers["If-Modified-Since"], out var dt) && dt > DateTime.Now)
            {
                actionContext.Result = new StatusCodeResult(304);
                return;
            }
            if (!actionContext.ModelState.IsValid)
            {
                Dictionary<string, string> msgs = new Dictionary<string, string>();
                foreach (var item in actionContext.ModelState)
                {
                    if (TryGetMessage(item.Value.Errors.FirstOrDefault(), item.Key, out string message))
                    {
                        msgs.Add(item.Key, message);
                    }
                }
                actionContext.Result = new ObjectResult(Result.Fail(msgs.FirstOrDefault().Value, (int)ErrorType.ArgumentsError, msgs));
            }
            else
            {
                InjectionFactory.ImportsFormFactory(actionContext.HttpContext.RequestServices, actionContext.Controller);
            }
        }
    }
}
